/*==============================================================================
            Copyright (c) 2013 Moritz Hader, Marcel Schrder
            All Rights Reserved.

	@file  MatrixManagementUnit.h

	@brief This header provides the class-definitions used by the MatrixManagementUnit.
	General purpose of this class is to maintain a List of matrices and allow operations
	upon these. The idea is, that operations, like rotation or translation,
	wont require array, handly by the user, but instead are handled by the method in here.
   
   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/

#include <egl/MatrixManagementUnit.h>

MatrixManagementUnit::MatrixManagementUnit(){
	this->size = 16; //Default Size
	this->index = 0; //Index denotes the currently selected element in the array. As the array is empty, the index is 0

	//Initialize the array
	this->matrices = new H44DMatrix[this->size];

		//Load the current layer with an identity matrix
		MakeInitialMatrix(this->matrices[0]);
}

MatrixManagementUnit::MatrixManagementUnit(int tsize){
	this->size = tsize; //Default Size
	this->index = 0; //Index denotes the currently selected element in the array. As the array is empty, the index is 0

	//Initialize the array
	this->matrices = new H44DMatrix[this->size];

		//Load the current layer with an identity matrix
		MakeInitialMatrix(this->matrices[0]);
}

MatrixManagementUnit::~MatrixManagementUnit(){
	if(this->matrices != NULL){
		delete[] this->matrices;
	}
}

/**
 * Push the given parameter into the list. The index is automatically increased
 */
void MatrixManagementUnit::AddMatrix(H44DMatrix matrix){

	if(this->index < this->size){ //Only push, if the border is not reached
		this->index++;
		memcpy(this->matrices[this->index],matrix,sizeof(H44DMatrix));
	}
}

/**
 * Copy the current Matrix. The index is automatically increased
 */
void MatrixManagementUnit::AddMatrix(){

	if(this->index < this->size){ //Only push, if the border is not reached
		this->index++;
		memcpy(this->matrices[this->index],this->matrices[this->index-1],sizeof(H44DMatrix));
	}
}

/**
 *Overwrite the selected Matrix with the provided matrix
 */
void MatrixManagementUnit::SetMatrix(H44DMatrix matrix){

	memcpy(this->matrices[this->index],matrix,sizeof(H44DMatrix));
}

/*
 * Write the current index-matrix into the parameter
 */
void MatrixManagementUnit::GetMatrix(H44DMatrix matrix){
	memcpy(matrix, this->matrices[this->index],sizeof(H44DMatrix));
}

/**
 * Drop the upper bond of the matrix-list
 */
void MatrixManagementUnit::DropMatrix(){

	if(this->index > 0){ //Only drop, if the index is above 0 (first element)
		this->index--;
		//Cleanup??? Dunno if necessary, after all, the array persists over the whole time...
	}
}

/**
 * Multiplies the provided matrix with the currently selected matrix (by index).
 * The selected matrix is overwritten by the result.
 */
void MatrixManagementUnit::MultiplyWithMatrix(H44DMatrix matrix){

	//As we are going to save the result back into the array, we need to remember the old values
	H44DMatrix oldVal;
		memcpy(oldVal, this->matrices[this->index],sizeof(H44DMatrix));

	//Perform the multiplication
	H3DMatrixMultiply44(this->matrices[this->index], matrix, oldVal);
}

/**
 * Multiplies the currently selected matrix with the provided matrix.
 * The selected matrix is overwritten by the result.
 */
void MatrixManagementUnit::MultiplyMatrixWith(H44DMatrix matrix){

	//As we are going to save the result back into the array, we need to remember the old values
	H44DMatrix oldVal;
		memcpy(oldVal, this->matrices[this->index],sizeof(H44DMatrix));

	//Perform the multiplication
	H3DMatrixMultiply44(this->matrices[this->index], oldVal, matrix);
}
